package com.sanhuo.security.uitls;

import com.sanhuo.security.UserVo;
import com.sanhuo.utils.basic.BeanUtil;
import com.sanhuo.utils.basic.StringUtil;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class UserHolder {
    private static String dataPath = "c:\\user.txt";
    private static String keyPath = "c:\\key.txt";


    /**
     * 存放数据的map
     */
    private static Map<String, Object> elementData = new ConcurrentHashMap<>();
    /**
     * 存放key
     */
    private static LinkedList<String> keyList = new LinkedList<>();


    static {
        init();
    }
    /**
     * 过期时间(min)
     */
    private static int overdueTime = 60;

    /**
     * map最大容量
     */

    private static final Integer MAX_NUMBER = 100;

    /**
     * 当前map容量
     */
    private static Integer ACTURAL_SIZE = 0;

    /**
     * 定时删除的定时器
     */
    private static ScheduledExecutorService service = Executors
            .newSingleThreadScheduledExecutor();

    /**
     * 获取实例
     *
     * @return
     */
    public static UserVo user() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getParameter("token");
        if (StringUtil.isBlank(token)) {
            token = (String) request.getAttribute("token");
        }
        /*
            找不到(或者是服务器重启了)从文件中找,再找不到说明没有
         */
        if (elementData.size() == 0) {
            getDataFromFile();

        }
        UserVo result = (UserVo) elementData.get(token);
        return result;
    }

    /**
     * 添加
     *
     * @param key
     * @param userVo
     */
    public static void put(String key, UserVo userVo) {
        checkSize();
        checkDate();
        elementData.put(key, userVo);
        keyList.add(key);
        Runnable runnable = () -> remove(key);
        service.schedule(runnable, 60, TimeUnit.MINUTES);
        toFile();

    }

    /**
     * 初始化
     */
    private static void init() {
        File data = new File(dataPath);
        File key = new File(keyPath);
        if (!data.exists() && !key.exists()) {
            toFile();
        }
    }

    /**
     * 清空所有
     */
    public static void clean() {
        checkDate();
        keyList.clear();
        elementData.clear();
        service.shutdown();
        service.shutdownNow();
    }

    /**
     * 删除指定的token对应的数据
     *
     * @param key
     */
    public static void remove(String key) {
        checkDate();
        if (keyList.contains(key)) {
            keyList.remove(key);
        }
        if (elementData.containsKey(key)) {
            elementData.remove(key);
        }

        toFile();
    }

    /**
     * 判断map和list是否为空,是从文件读取一次
     */
    public static void checkDate() {
        if (BeanUtil.isNull(keyList) && BeanUtil.isNull(elementData)) {
            getDataFromFile();
        }
    }

    /**
     * 判断长度
     */
    private static void checkSize() {
        //实际长度大于最大长度,删除最久的一个数据
        if (ACTURAL_SIZE >= MAX_NUMBER) {
            deleteOldest();
        }
    }

    /**
     * 删除最久的一个数据
     */
    private static void deleteOldest() {
        String firstKey = keyList.removeFirst();
        elementData.remove(firstKey);
    }


    private static void toFile() {

        ObjectOutputStream dataOos = null;
        ObjectOutputStream keyOos = null;
        try {
            dataOos = new ObjectOutputStream(new FileOutputStream(new File(dataPath)));
            keyOos = new ObjectOutputStream(new FileOutputStream(new File(keyPath)));
            dataOos.writeObject(elementData);
            keyOos.writeObject(keyList);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(dataOos);
            IOUtils.closeQuietly(keyOos);
        }
    }

    private static void getDataFromFile() {
        File data = new File(dataPath);
        File key = new File(keyPath);
        ObjectInputStream dataOis = null;
        ObjectInputStream keyOis = null;
        try {
            dataOis = new ObjectInputStream(new FileInputStream(data));
            keyOis = new ObjectInputStream(new FileInputStream(key));
            elementData = (ConcurrentHashMap) dataOis.readObject();
            keyList = (LinkedList) keyOis.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(dataOis);
            IOUtils.closeQuietly(keyOis);
        }
    }

}
